package com.ruoyi.common.utils;

import cn.hutool.core.util.StrUtil;
import com.ruoyi.common.exception.ItemNotFoundException;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

@Slf4j
public class ObjectUtil {

    public static void checkNull(Object obj, String nullTips) {
        checkNull(obj ,nullTips ,null);
    }

    public static void checkNull(Object obj , RuntimeException ex) {
        ex = ex == null ? new NullPointerException("") : ex;
        checkNull(obj ,null ,ex);
    }

    public static void checkNull(Object obj, String nullTips , RuntimeException ex) {
        if (Objects.isNull(obj)) {
            throw ex == null ? new ItemNotFoundException(nullTips) : ex;
        }
    }

    public static void checkEmpty(String val ,String emptyTips){
        if (StrUtil.isEmpty(val)) {
            throw new ItemNotFoundException(emptyTips);
        }
    }

    public static void checkEmpty(Collection collection ,String emptyTips){
        if (collection == null || collection.isEmpty()) {
            throw new ItemNotFoundException(emptyTips);
        }
    }

    public static void checkEmpty(Map map ,String emptyTips){
        if (map == null || map.isEmpty()) {
            throw new ItemNotFoundException(emptyTips);
        }
    }

    /**
     * 获取所有的属性
     * @param tClass 類型
     * @param includeParent 是否包含父类以上的属性
     * @return
     */
    public static <T> Field[] getAllFields(Class<T> tClass,boolean includeParent){
        Class supClazz;
        List<Field> fieldList = new ArrayList<>();
        if(tClass != null)
        {
            fieldList.addAll(new ArrayList<>(Arrays.asList(tClass.getDeclaredFields())));
            if(includeParent) {
                supClazz = tClass.getSuperclass();
                while (supClazz != null) {
                    fieldList.addAll(new ArrayList<>(Arrays.asList(supClazz.getDeclaredFields())));
                    supClazz = supClazz.getSuperclass();
                }
            }
        }
        Field[] fields = new Field[fieldList.size()];
        fieldList.toArray(fields);
        return fields;
    }

    /**
     * 获取所有的属性
     * @param object
     * @param includeParent 是否包含父类以上的属性
     * @return
     */
    public static Field[] getAllFields(Object object,boolean includeParent){
        return getAllFields(object.getClass(),includeParent);
    }

    /**
     * 根据属性名获取属性值
     * @param obj 源数据
     * @param fieldName 字段名
     * @return
     */
    public static Object getVal(Object obj,String fieldName) {
        try {
            String firstLetter = fieldName.substring(0, 1).toUpperCase();
            String getter = "get" + firstLetter + fieldName.substring(1);
            Method method = obj.getClass().getMethod(getter, new Class[] {});
            Object value = method.invoke(obj, new Object[] {});
            return value;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 根据属性名设置属性值
     * @param object 要设置的对象
     * @param fieldName 字段名
     * @param value 字段值
     */
    public static void setVal(Object object,String fieldName, Object value) {
        try {
            // 获取obj类的字节文件对象
            Class c = object.getClass();
            // 获取该类的成员变量
            Field f = c.getDeclaredField(fieldName);
            // 取消语言访问检查
            f.setAccessible(true);
            // 给变量赋值
            f.set(object, value);
        } catch (Exception e) {
            log.error(e.getMessage(),e);
        }
    }

    /**
     * 一个对象填充另一个对象
     * @param source 源对象
     * @param sfields 需要填充的属性
     * @param data 数据提供对象
     */
    public static void FillEntity(Object source, Field[] sfields, Object data) {
        try {
            Field[] dfields = getAllFields(data,true);
            for (Field dfield : dfields) {
                Field sfield = Arrays.stream(sfields).filter(x -> dfield.getName().equals(x.getName())).findFirst().orElse(null);
                if(sfield == null)
                    continue;
                if(sfield.getGenericType() == dfield.getGenericType())
                {
                    sfield.setAccessible(true);
                    // 给变量赋值
                    sfield.set(source, getVal(data,dfield.getName()));
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage(),e);
        }
    }

    /**
     * 一个对象填充另一个对象
     * @param source 源对象
     * @param data 数据提供对象
     */
    public static void FillEntity(Object source, Object data) {
        try {
            Field[] sfields = getAllFields(data,true);
            FillEntity(source, sfields, data);
        } catch (Exception e) {
            log.error(e.getMessage(),e);
        }
    }
}
